Lab 10 - OpenGL

Lab 10 - OpenGL

OpenGL i GLU w SFML

OpenGL jest otwartym, niskopoziomowym API pozwalającym na generowanie trójwymiarowej grafiki. Ponieważ biblioteka SFML wykorzystuje wewnętrznie OpenGL do rysowania grafiki 2D, możemy ją wykorzystać jako bibliotekę pomocniczą ułatwiającą np. utworzenie okna i obsługę zdarzeń (np. obsługę urządzeń wejścia jak myszka czy klawiatura).

OpenGL dostarcza m.in. funkcje rysujące pojedyncze wielokąty lub serie wielokątów oraz ich przekształcenia. Nieco bardziej wysokopoziomowe funkcje są częścią biblioteki GLU (GL Utilility Library).

Ponieważ będziemy wykorzystywać bezpośrednio funkcje OpenGL oraz GLU, wymagane jest dołączenie ich do listy bibliotek dla przekazanych w parametrach linkerowi. W przypadku środowiska Qt Creator, dodajemy do pliku .pro poniższą linię:

LIBS += -lOpenGL32 -lglu32

Pierwszy program OpenGL + SFML

Stwórz projekt do pracy z SFML oraz OpenGL. Umieść w projekcie plik main.cpp z zawartością pobraną z odnośnika sfml_opengl.cpp.

Uruchom program. Na ekranie powinien się pojawić obracający się kolorowy sześcian.

Struktura kodu programu jest analogiczna do poprzednich programów SFML - następuje inicjalizacja środowiska (w tym parametrów OpenGL, takich jak np. model oświetlenia), a następnie, w głównej pętli, rysowane są klatki obrazu.

W trójwymiarowej grafice komputerowej najczęściej wykorzystuje się reprezentację brył w postaci siatki wielokątów - każdy obiekt zbudowany jest z płaskich wielokątów (najczęściej trójkątów lub czworokątów), które mają wspólne wierzchołki i krawędzie. Pozwala to w łatwy sposób stworzyć proste bryły, a także przybliżyć skomplikowane obiekty dostatecznie gęstą siatką.

Załączona funkcja rysująca sześcian rysuje każdą z jego ścian jako kwadrat, w różnych kolorach.

Aby zapewnić stałe proporcje wyświetlanego obrazu i zakres widoczności w pionie, po każdym evencie typu sf::Event::Resized (zmiana rozmiaru okna), wywoływana jest funkcja set_viewport. Funkcja ta wykorzystując informacje o nowym rozmiarze okna ustawia odpowiednio zakres widzianej sceny (glFrustrum) oraz ustawia pozycję kamery (gluLookAt).

Transformacje geometryczne w OpenGL

Aplikacje OpenGL wykorzystują układ współrzędnych do lokalizacji obiektów na scenie. Aby uniknąć konieczności ręcznego przeliczania położeń wierzchołków obiektów na scenie, układ ten można transformować (m.in. przesuwać i obracać): * glTranslated(double x, double y, double z) - przesuwa układ współrzędnych o odległości podane jako argumenty, * glRotated(double angle, double x, double y, double z) - obraca układ współrzędnych o kąt angle (w stopniach) wokół osi zdefiniowanej przez parametry x, y, z.

Należy pamiętać, że kolejność ma istotne znaczenie. Rozważ poniższe przykłady:

Translation then rotation
Rotation then translation

W efekcie wykonanie tych samych operacji (ale w innej kolejności) daje inny efekt - porównaj położenie oraz orientację samolotu w obu przypadkach.

W celu ułatwienia powrotu do punktu wyjścia (np. po wykonaniu szeregu przekształceń) udostępniono następujące funkcje: * glPushMatrix() - zapisuje aktualny stan (położenie oraz orientację) układu współrzędnych, * glPopMatrix() - pobiera ostatnio zapisany stan (położenie oraz orientację) układu współrzędnych. Należy pamiętać, że dla każdego wywołania glPushMatrix() obowiązkowo należy wywołać jedno glPopMatrix(). Można traktować je jak klamry opasające fragment kodu, którego tyczą się przekształcenia.

Rozważmy przykład przedstawiony na rysunku poniżej:

Rotation then translation

Planujemy narysować dwa samoloty - w punkcie (4, 4), a następnie (2, 1). Bez wykorzystania funkcji glPushMatrix() / glPopMatrix() (operacje przedstawione nad obrazkiem) niezbędne jest wyliczenie jak przesunąć się z punktu (4, 4) do (2, 1). W zaprezentowanym przykładzie wydaje się to łatwe, ale przekształceń może być więcej i mogą być wśród nich rotacje komplikujące zadanie. Z wykorzystaniem funkcji glPushMatrix() / glPopMatrix() (operacje pod rysunkiem) zadanie jest mniej skomplikowane - nie trzeba wykonywać żadnych transformacji odwrotnych - wystarczy na początku zapamiętać aktualny stan, a później do niego powrócić.

Poza przesuwaniem i obracaniem układu można go również skalować (funkcja glScaled()).

Zadanie końcowe 🛠🔥

1. Planetarium

Napisz program obrazujący ruch planet w Układzie Słonecznym.

Napisz klasę CelestialBody reprezentującą ciało niebieskie - aby lepiej widzieć ruch obrotowy planet, możesz reprezentować je jako sześciany.

Cechy ciała niebieskiego:

Klasa powinna mieć metodę step(float time) (analogicznie do programów z poprzednich zajęć) oraz draw() powodującą narysowanie planety.

Zastanów się nad kolejnością transformacji potrzebnych do narysowania planety w odpowiednim miejscu i o odpowiednim kącie obrotu (podpowiedź: nie potrzebujesz trygonometrii!).

Wczytaj zawartość pliku solar_system.txt i na jego podstawie utwórz obiekty na scenie reprezentujące wszystkie planety i słońce. Uwaga: odległości i średnice w pliku są zmodyfikowane tak, aby wizualizacja pozostała czytelna. Prawdziwe wartości można znaleźć w pliku solar_system_real.txt


Autorzy: Tomasz Mańkowski, Jakub Tomczyński